package it.uniroma2.mpsr.algorithms;

import it.uniroma2.mpsr.resources.Centre;
import it.uniroma2.mpsr.resources.MVAResults;
import it.uniroma2.mpsr.utils.Misc;

public class MVA {

	public static MVAResults solve(double[][] routing, Centre[] centres, int N) {

		double[] weights = new double[centres.length];
		for(int i = 0; i < centres.length; i++)
			weights[i] = 1;

		double[] y = Misc.solveSystem(routing, weights, 0, 1);
		if(y == null)
			return null;

		/*********************Rapporti tra visite***********************/
		double[][] v = new double[routing.length][routing.length];
		for(int i=0; i < routing.length; i++) {
			for(int j=0; j < routing.length; j++) {
				if(y[j] != 0)
					v[i][j] = y[i] / y[j];
			}
		}
		/***************************************************************/

		double[][] population = new double[N+1][centres.length];
		double[][] lambda = new double[N+1][centres.length];
		double[][] residenceTime = new double[N+1][centres.length];

		for(int n = 1; n <= N; n++) {
			for(int i = 0; i < centres.length; i++) {
				/******tempo di residenza per la n-esima iterazione e l'i-esimo centro*****/
				if(centres[i].getKind().equals("SPC"))
					residenceTime[n][i] = centres[i].getServiceTime() * (1 + population[n-1][i]);
				else
					// centro IS
					residenceTime[n][i] = centres[i].getServiceTime();
			}
			for(int i = 0; i < centres.length; i++) {
				double den = 0;
				for(int j = 0; j < centres.length; j++) {
					den += residenceTime[n][j] * v[j][i];
				}
				if(den != 0)
					/******throughput per la n-esima iterazione e l'i-esimo centro*****/
					lambda[n][i] = n / den;
				/******popolazione media per la n-esima iterazione e l'i-esimo centro*****/
				population[n][i] = lambda[n][i] * residenceTime[n][i];
			}
		}
		
		/*********************Tempi medi di risposta**********************/
		double[] responseTime = new double[centres.length]; 
		for(int i = 0; i < centres.length; i++) {
			for(int j = 0; j < centres.length; j++) {
				if(i != j) {
					responseTime[i] += residenceTime[N][j] * v[j][i];
				}
			}
		}
		/*****************************************************************/

		/***************************Utilizzazioni*************************/
		double[][] U = new double[N+1][centres.length];
		for (int n = 0; n <= N; n++) {
			for(int i = 0; i < lambda[N].length; i++) {
				U[n][i] = lambda[n][i] / (centres[i].getMu() * centres[i].getMultiplicity());
			}
		}
		/***************************************************************/
		
		
		/****************Tempo di ciclo*********************************/
		double[] cycleTime = new double[centres.length];
		for (int i = 0;i < centres.length; i++) {
			cycleTime[i] = responseTime[i] + residenceTime[N][i];
		}
			
		/************************************************************/

		/**************Throughput dell impianto***************************/
		double[] totThroughput = new double[centres.length];
		for(int i=0; i < centres.length;i++) {
			totThroughput[i] = N / cycleTime[i];
		}
		/************************************************************/
		
		//		System.out.println(Arrays.toString(responseTime));
		return new MVAResults(centres, residenceTime[N], lambda[N], population[N], responseTime, U[N], cycleTime, totThroughput);
	}


}
